/**
 * createStore(reducer, preloadedState, enhancer) 
 * { getState, dispatch, subscribe }
 */

 function createStore (reducer, preloadedState, enhancer) {
  //  约束 reducer 参数类型
  if (typeof reducer !== 'function') {
    throw new Error('reducer 必须是函数')
  }
  // 判断 enhancer 参数有没有传递
  if (typeof enhancer !== 'undefined') {
    // 判断 enhancer 是不是一个函数
    if (typeof enhancer !== 'function') {
      throw new Error('enhancer 必须是一个函数')
    }
    return enhancer(createStore)(reducer, preloadedState)
  }
  // store 对象中存储的状态
  var currentState = preloadedState
  var currentListeners = []
  
  // 获取状态
  function getState () {
    return currentState
  }

  // 触发action
  function dispatch (action) {
    // 判断 action 是否是对象
    if (!isPlainObject(action)) {
      throw new Error('action 必须是对象')
    }
    // 判断对象中是否具有type属性
    if (typeof action.type === 'undefined') {
      throw new Error('action 中必须具有 type 属性')
    }
    currentState = reducer(currentState, action)
    // 循环数组，调用订阅者
    for (var i = 0 ; i < currentListeners.length; i++) {
      // 获取订阅者
      var listener = currentListeners[i]
      // 调用订阅者
      listener()
    }
  }

  // 订阅状态
  function subscribe (listener) {
    currentListeners.push(listener)
  }

  return {
    getState,
    dispatch,
    subscribe
  }
 }

 // 判断 obj 参数是否是对象
 function isPlainObject (obj) {
  // 排除基本数据类型和null
  if (typeof obj !== 'object' || obj === null) {
    return false
  }
  // 区分数组和对象： 原型对象对比的方式
  var proto = obj
  while (Object.getPrototypeOf(proto) !== null) {
    proto = Object.getPrototypeOf(proto)
  }
  return Object.getPrototypeOf(obj) === proto
 }

 function applyMiddleware (...middlewares) {
  return function (createStore) {
    return function (reducer, preloadedState) {
      // 创建 store
      var store = createStore(reducer, preloadedState)
      // 阉割版的 store
      var middlewareAPI = {
        getState: store.getState,
        dispatch: store.dispatch
      }
      // 调用中间件的第一层函数 传递阉割版的 store 对象
      var chain = middlewares.map(middleware => middleware(middlewareAPI))
      var dispatch = compose(...chain)(store.dispatch)
      return {
        ...store,
        dispatch
      }
    }
  }
 }

 function compose () {
    var funcs = [...arguments]
    return function (dispatch) {
      for (var i = funcs.length - 1; i >= 0; i--) {
        dispatch = funcs[i](dispatch)
      }
      return dispatch
    }
 }

 function bindActionCreators (actionCreators, dispatch) {
  var boundActionCreators = {}
  for (var key in actionCreators) {
    (function (key) {
      boundActionCreators[key] = function () {
        dispatch(actionCreators[key]())
      }
    })(key)
  }
  return boundActionCreators
 }

 function combineReducers (reducers) {
   // 1. 检查 reducer 类型，它必须是函数
   var reducerKeys = Object.keys(reducers)
   for (var i = 0; i < reducerKeys.length; i++) {
     var key = reducerKeys[i]
     if (typeof reducers[key] !== 'function') {
       throw new Error('reducer 必须是函数')
     }
   }
   // 2. 调用一个一个小的 reducer，将每一个 reducer 中返回的状态存储在一个新的大的对象中
   return function (state, action) {
    var nextState = {}
    for (var i = 0; i < reducerKeys.length; i++) {
      var key = reducerKeys[i]
      var reducer = reducers[key]
      var previousStateForKey = state[key]
      nextState[key] = reducer(previousStateForKey, action)
    }
    return nextState
   }
 }